/*
 * Copyright (C) 2020 xuexiangjys(xuexiangjys@163.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package com.xuexiang.xui_lib.component.button.shinebutton;

import com.xuexiang.xui_lib.util.AttrValue;

import ohos.aafwk.ability.Ability;
import ohos.aafwk.ability.fraction.Fraction;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.DirectionalLayout;
import ohos.agp.utils.Color;
import ohos.agp.window.dialog.CommonDialog;
import ohos.agp.window.service.Display;
import ohos.agp.window.service.DisplayManager;
import ohos.app.Context;
import ohos.hiviewdfx.HiLog;

/**
 * 增强效果的按钮
 *
 * @author xuexiang
 * @since 2020-01-06
 */
public class ShineButton extends PorterShapeImageView {
    private static final int NUM700 = 700;
    private static final int NUM180 = 180;
    private static final float NUM0_2 = 0.2f;
    private static final float NUM0_8 = 0.8f;
    private static final float NUM0_9 = 0.9f;
    AddRootViewListener addRootViewListener;
    ComponentContainer rootV = null;
    ShineView nowShineView = null;
    private OnClickListenWrapper mOnClickListenWrapper;
    private boolean mIsChecked = false;

    private int mNormalColor;
    private int mCheckedColor;

    private AnimatorValue mShakeAnimator;
    private ShineView.ShineParams mShineParams = new ShineView.ShineParams();

    private OnCheckedChangeListener mOnCheckedChangeListener;

    //private boolean mIsDialog;

   /* *//**
     * ShineButton
     *
     * @param context
     *//*
    public ShineButton(Context context) {
        this(context, null);
    }*/

    /**
     * ShineButton
     *
     * @param context
     * @param attrs
     */
    public ShineButton(Context context, AttrSet attrs) {
        this(context, attrs, 0);
    }

    /**
     * ShineButton
     *
     * @param context
     * @param attrs
     * @param defStyleAttr
     */
    public ShineButton(Context context, AttrSet attrs, int defStyleAttr) {
        super(context, attrs);
        initButton(context, attrs);
    }

    private void initButton(Context context, AttrSet attrs) {
        if (attrs.getAttr("sb_normal_color").isPresent()) {
            mNormalColor = attrs.getAttr("sb_normal_color").get().getColorValue().getValue();
        } else {
            mNormalColor = Color.getIntColor("#AAAAAA");
        }
        if (attrs.getAttr("sb_checked_color").isPresent()) {
            mCheckedColor = attrs.getAttr("sb_checked_color").get().getColorValue().getValue();
        } else {
            mCheckedColor = Color.getIntColor("#FFFFFF");
        }

        mShineParams.allowRandomColor = AttrValue.get(attrs, "sb_allow_random_color", false);
        mShineParams.animDuration = AttrValue.get(attrs, "sb_shine_animation_duration",
            (int) mShineParams.animDuration);
        mShineParams.clickAnimDuration = AttrValue.get(attrs, "sb_click_animation_duration",
            (int) mShineParams.clickAnimDuration);
        mShineParams.enableFlashing = AttrValue.get(attrs, "sb_enable_flashing", false);
        mShineParams.shineDistanceMultiple = AttrValue.get(attrs, "sb_shine_distance_multiple",
            mShineParams.shineDistanceMultiple);
        mShineParams.shineCount = AttrValue.get(attrs, "sb_shine_count", mShineParams.shineCount);
        mShineParams.shineSize = AttrValue.get(attrs, "sb_shine_size", mShineParams.shineSize);
        mShineParams.shineTurnAngle = AttrValue.get(attrs, "sb_shine_turn_angle", mShineParams.shineTurnAngle);
        mShineParams.smallShineOffsetAngle = AttrValue.get(attrs, "sb_small_shine_offset_angle",
            mShineParams.smallShineOffsetAngle);
        if (attrs.getAttr("sb_small_shine_color").isPresent()) {
            mShineParams.smallShineColor = attrs.getAttr("sb_small_shine_color").get().getColorValue().getValue();
        }
        if (attrs.getAttr("sb_big_shine_color").isPresent()) {
            mShineParams.bigShineColor = attrs.getAttr("sb_big_shine_color").get().getColorValue().getValue();
        }

        setTintColor(mNormalColor);

        if (context instanceof Ability) {
            initWindow((Ability) context);
        }

        mOnClickListenWrapper = new OnClickListenWrapper();
        setClickedListener(mOnClickListenWrapper);
    }

    /**
     * 修复对话框中显示的问题
     *
     * @param dialog
     */
    public void fitDialog(CommonDialog dialog) {
        //mIsDialog = true;
    }

    /**
     * fitFragment
     *
     * @param fragment
     */
    public void fitFragment(Fraction fragment) {
        initWindow(fragment.getFractionAbility());
    }

    /**
     * getColor
     *
     * @return int
     */
    public int getColor() {
        return mCheckedColor;
    }

    /**
     * setNormalColor
     *
     * @param normalColor
     * @return ShineButton
     */
    public ShineButton setNormalColor(int normalColor) {
        mNormalColor = normalColor;
        setTintColor(mNormalColor);
        return this;
    }

    /**
     * setCheckedColor
     *
     * @param checkedColor
     * @return ShineButton
     */
    public ShineButton setCheckedColor(int checkedColor) {
        mCheckedColor = checkedColor;
        return this;
    }

    /**
     * setChecked
     *
     * @param checked
     * @param anim
     */
    public void setChecked(boolean checked, boolean anim) {
        setChecked(checked, anim, true);
    }

    private void setChecked(boolean checked, boolean anim, boolean callBack) {
        mIsChecked = checked;
        if (checked) {
            setTintColor(mCheckedColor);
            mIsChecked = true;
            if (anim) {
                showAnim();
            }
        } else {
            setTintColor(mNormalColor);
            mIsChecked = false;
            if (anim) {
                setCancel();
            }
        }
        if (callBack) {
            onCheckedChanged(checked);
        }
    }

    private void onCheckedChanged(boolean checked) {
        if (mOnCheckedChangeListener != null) {
            mOnCheckedChangeListener.onCheckedChanged(this, checked);
        }
    }

    /**
     * setCancel
     */
    public void setCancel() {
        setTintColor(mNormalColor);
        if (mShakeAnimator != null) {
            mShakeAnimator.end();
            mShakeAnimator.cancel();
        }
    }

    /**
     * setAllowRandomColor
     *
     * @param allowRandomColor
     * @return ShineButton
     */
    public ShineButton setAllowRandomColor(boolean allowRandomColor) {
        mShineParams.allowRandomColor = allowRandomColor;
        return this;
    }

    /**
     * setAnimDuration
     *
     * @param durationMs
     * @return ShineButton
     */
    public ShineButton setAnimDuration(int durationMs) {
        mShineParams.animDuration = durationMs;
        return this;
    }

    /**
     * setBigShineColor
     *
     * @param color
     * @return ShineButton
     */
    public ShineButton setBigShineColor(int color) {
        mShineParams.bigShineColor = color;
        return this;
    }

    /**
     * setClickAnimDuration
     *
     * @param durationMs
     * @return ShineButton
     */
    public ShineButton setClickAnimDuration(int durationMs) {
        mShineParams.clickAnimDuration = durationMs;
        return this;
    }

    /**
     * enableFlashing
     *
     * @param enable
     * @return ShineButton
     */
    public ShineButton enableFlashing(boolean enable) {
        mShineParams.enableFlashing = enable;
        return this;
    }

    /**
     * setShineCount
     *
     * @param count
     * @return ShineButton
     */
    public ShineButton setShineCount(int count) {
        mShineParams.shineCount = count;
        return this;
    }

    /**
     * setShineDistanceMultiple
     *
     * @param multiple
     * @return ShineButton
     */
    public ShineButton setShineDistanceMultiple(float multiple) {
        mShineParams.shineDistanceMultiple = multiple;
        return this;
    }

    /**
     * setShineTurnAngle
     *
     * @param angle
     * @return ShineButton
     */
    public ShineButton setShineTurnAngle(float angle) {
        mShineParams.shineTurnAngle = angle;
        return this;
    }

    /**
     * setSmallShineColor
     *
     * @param color
     * @return ShineButton
     */
    public ShineButton setSmallShineColor(int color) {
        mShineParams.smallShineColor = color;
        return this;
    }

    /**
     * setSmallShineOffAngle
     *
     * @param angle
     * @return ShineButton
     */
    public ShineButton setSmallShineOffAngle(float angle) {
        mShineParams.smallShineOffsetAngle = angle;
        return this;
    }

    /**
     * setShineSize
     *
     * @param size
     * @return ShineButton
     */
    public ShineButton setShineSize(int size) {
        mShineParams.shineSize = size;
        return this;
    }

    @Override
    public void setClickedListener(ClickedListener listener) {
        if (listener instanceof OnClickListenWrapper) {
            super.setClickedListener(listener);
        } else {
            if (mOnClickListenWrapper != null) {
                mOnClickListenWrapper.wrapListener(listener);
            }
        }
    }

    /**
     * initWindow
     *
     * @param activity
     */
    public void initWindow(Ability activity) {
        //mIsDialog = false;
    }

    /**
     * setAddRootViewListener
     *
     * @param addRootViewListener
     */
    public void setAddRootViewListener(AddRootViewListener addRootViewListener) {
        this.addRootViewListener = addRootViewListener;
    }

    /**
     * AddRootViewListener
     *
     * @since 2019-05-12
     */
    public interface AddRootViewListener {
        /**
         * getWindowRootView
         *
         * @return ComponentContainer
         */
        ComponentContainer getWindowRootView();
    }

    public ComponentContainer getWindowViewGroup() {
        return addRootViewListener.getWindowRootView();
    }

    /**
     * removeRootView
     */
    public void removeRootView() {
        if (rootV != null && nowShineView != null) {
            rootV.removeComponent(nowShineView);
        }
    }

    /**
     * showAnim
     */
    public void showAnim() {
        ShineView shineView = new ShineView(getContext(), this, mShineParams);
        ComponentContainer rootView = addRootViewListener.getWindowRootView();
        Display display = DisplayManager.getInstance().getDefaultDisplay(mContext).get();
        ComponentContainer.LayoutConfig layoutConfig = new DirectionalLayout.LayoutConfig();
        layoutConfig.width = display.getAttributes().width;
        layoutConfig.height = display.getAttributes().height;
        rootView.addComponent(shineView, layoutConfig);
        rootV = rootView;
        nowShineView = shineView;
        doShareAnim();
    }

    private void doShareAnim() {
        mShakeAnimator = new AnimatorValue();
        mShakeAnimator.setDuration(NUM700);
        mShakeAnimator.setDelay(NUM180);

        mShakeAnimator.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
            @Override
            public void onUpdate(AnimatorValue animatorValue, float value) {
                float tempV = value + NUM0_2;
                if (NUM0_8 < value) {
                    setScaleX(1 - (value - NUM0_8));
                    setScaleY(1 - (value - NUM0_8));
                    if (NUM0_9 < value) {
                        setScaleX(value);
                        setScaleY(value);
                    }
                } else {
                    setScaleX(tempV);
                    setScaleY(tempV);
                }
                invalidate();
            }
        });

        mShakeAnimator.setStateChangedListener(new Animator.StateChangedListener() {
            @Override
            public void onStart(Animator animator) {
                setTintColor(mCheckedColor);
            }

            @Override
            public void onStop(Animator animator) {
            }

            @Override
            public void onCancel(Animator animator) {
                setTintColor(mNormalColor);
            }

            @Override
            public void onEnd(Animator animator) {
                setTintColor(mIsChecked ? mCheckedColor : mNormalColor);
            }

            @Override
            public void onPause(Animator animator) {

            }

            @Override
            public void onResume(Animator animator) {

            }
        });
        mShakeAnimator.start();
    }

    /**
     * OnClickListenWrapper
     *
     * @since 2019-05-12
     */
    public class OnClickListenWrapper implements ClickedListener {
        private ClickedListener mListener;

        OnClickListenWrapper() {
        }

        /**
         * OnClickListenWrapper
         *
         * @param listener
         */
        public OnClickListenWrapper(ClickedListener listener) {
            mListener = listener;
        }

        /**
         * wrapListener
         *
         * @param listener
         */
        public void wrapListener(ClickedListener listener) {
            mListener = listener;
        }

        @Override
        public void onClick(Component view) {
            HiLog.info(LABEL, "mIsChecked: " + mIsChecked);
            if (!mIsChecked) {
                mIsChecked = true;
                setTintDrawable(true);
                showAnim();
            } else {
                mIsChecked = false;
                setTintDrawable(false);
                setCancel();
            }
            onCheckedChanged(mIsChecked);
            if (mListener != null) {
                mListener.onClick(view);
            }
        }
    }

    /**
     * setOnCheckStateChangeListener
     *
     * @param listener
     * @return ShineButton
     */
    public ShineButton setOnCheckStateChangeListener(OnCheckedChangeListener listener) {
        mOnCheckedChangeListener = listener;
        return this;
    }

    /**
     * 点击切换的监听
     *
     * @since 2020-03-15
     */
    public interface OnCheckedChangeListener {
        /**
         * 选中状态改变
         *
         * @param shineButton
         * @param isChecked
         */
        void onCheckedChanged(ShineButton shineButton, boolean isChecked);
    }

}
